% Created 2018-10-16 Tue 11:07
% Intended LaTeX compiler: pdflatex
\documentclass[11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{graphicx}
\usepackage{grffile}
\usepackage{longtable}
\usepackage{wrapfig}
\usepackage{rotating}
\usepackage[normalem]{ulem}
\usepackage{amsmath}
\usepackage{textcomp}
\usepackage{amssymb}
\usepackage{capt-of}
\usepackage{hyperref}
\author{张海斌}
\date{\today}
\title{bomb 实验报告}
\hypersetup{
 pdfauthor={张海斌},
 pdftitle={bomb 实验报告},
 pdfkeywords={},
 pdfsubject={},
 pdfcreator={Emacs 25.2.2 (Org mode 9.1.14)}, 
 pdflang={English}}
\begin{document}

\maketitle
\tableofcontents


\section{入门}
\label{sec:org0986c66}

\href{https://www.cnblogs.com/zengkefu/p/5571500.html}{gdb - 列出所有函数调用} 在这篇博客以及其他网站包括官方文档中，我找到了输出 bomb 中函数并将其写入 log 文件的方法。

\begin{verbatim}
$ gdb bomb
(gdb) set logging file func.txt  # 修改 log 输出文件
(gdb) set logging on  # 开启 log 记录
(gdb) set confirm off  # 关闭输出确认，使结果连续打印出来
(gdb) set logging off
\end{verbatim}

之后在 \texttt{func.txt} 文件中，搜索 \texttt{phase} 找到了 \texttt{phase\_1} \texttt{phase\_2} \texttt{phase\_3} \texttt{phase\_4} \texttt{phase\_5} \texttt{phase\_6} \texttt{secret\_phase} \texttt{invalid\_phase} \texttt{phase\_defused} 这 9 个函数(虽然其中很多都在 \texttt{bomb.c} 中出现过了 ☺)。
再搜索 \texttt{bomb} 找到了 \texttt{initialize\_bomb} \texttt{initialize\_bomb\_solve} \texttt{explode\_bomb} 3 个函数。

\section{phase\(_{\text{1}}\)}
\label{sec:orgbd839f6}

\begin{verbatim}
$ gdb bomb
(gdb) b phase_1  # 在 phase_1 函数处设置断点
(gdb) r  # 运行程序
(gdb) layout regs  # 切换到 regs 的 layout，同时显示寄存器数据和汇编代码
\end{verbatim}

在汇编代码中可以看到

\begin{verbatim}
B+> 0x400ee0 <phase_1>      sub    $0x8,%rsp                                                                                                                 │
    0x400ee4 <phase_1+4>    mov    $0x402400,%esi                                                                                                            │
    0x400ee9 <phase_1+9>    callq  0x401338 <strings_not_equal>  
    0x400eee <phase_1+14>   test   %eax,%eax                                                                                                                 │
    0x400ef0 <phase_1+16>   je     0x400ef7 <phase_1+23>                                                                                                     │
    0x400ef2 <phase_1+18>   callq  0x40143a <explode_bomb>                                                                                                   │
    0x400ef7 <phase_1+23>   add    $0x8,%rsp                                                                                                                 │
    0x400efb <phase_1+27>   retq                                                                                                                             │
    0x400efc <phase_2>      push   %rbp    
\end{verbatim}

可以看到 \texttt{phase\_1} 函数只有几行，根据尖括号内调用函数名称可以知道函数功能，所以函数第二行肯定是将 phase1 在内存中的首地址赋值给寄存器 \%esi，所以只需要获取内存中的数据就可以得到 phase1。

\begin{verbatim}
(gdb) x/s 0x402400
0x402400:       "Border relations with Canada have never been better."
\end{verbatim}

所以得到 phase1 为 Border relations with Canada have never been better.

\section{phase\(_{\text{2}}\)}
\label{sec:orgeefe764}

在 \texttt{phase\_2} 中进入一个名为 \texttt{read\_six\_numbers} 的函数后（从函数名可以看出这个函数用来读取六个数字），首先经过一些操作（我没有管它在干啥），然后看到它调用 \texttt{\_\_isoc99\_sscanf@plt} 函数。从函数名可以知道这应该是一个 C99 标准下的 sscanf 函数，它读取两个字符串，将第一个字符串中的数值以 scanf 的方式读入到变量中。
第二个参数 \%esi 被赋值为 \$0x4025c3

\begin{verbatim}
(gdb) x/s 0x4025c3
0x4025c3:       "%d %d %d %d %d %d"
\end{verbatim}

这句调用从第一个字符串中读入六个整数，这验证了函数名的功能，最后判断是否读到 6 个数，否的话引爆炸弹。
可以将输入的六个数从 1 到 6 输入，这样方便 debug 时判断是第几个参数。
在读入六个数字之后程序回到 \texttt{phase\_2} 函数，重复运行几次，反复修改那 6 个数字。经过几次调试发现：后面是一个循环，遍历所有的数字，开始与 1 对比，之后对比的数不停加自己，就是乘 2。
所以得到结果 \texttt{1, 2, 4, 8, 16, 32}

\section{phase\(_{\text{3}}\)}
\label{sec:orge48bb61}

\texttt{phase\_3} 同样调用 \texttt{sscanf} 函数，读取内存地址 0x4025cf 的数据 \texttt{"\%d \%d"} 知道读取两个数字。
之后判断第一个数字是否超过 7，所以第一个数字要小于等于 7。
之后有一个 \texttt{jmpq   *0x402470(,\%rax,8)} 语句，后面出现了很多个 \texttt{jmp} 语句，而且跳转到相同的位置，所以这可能是 \texttt{switch} 语句。
不同的第一个数字要求的第二个数字不同，于是我将第一个数选为 6 ，找到对应需要的数字，修改第二个数字， \sout{但是却过不了} ，数据只读入了最后一位，所以重新在 \texttt{switch} 中找要求第二位只有一位的数，只有两个符合。
于是在 0 到 7 之间一个一个尝试，找到跳转位置，得到第一组结果 \texttt{0 207}
之后想到可以直接打印内存信息找到跳转位置：

\begin{verbatim}
(gdb) x/8xg 0x402470
0x402470:       0x0000000000400f7c      0x0000000000400fb9
0x402480:       0x0000000000400f83      0x0000000000400f8a
0x402490:       0x0000000000400f91      0x0000000000400f98
0x4024a0:       0x0000000000400f9f      0x0000000000400fa6
\end{verbatim}

于是找到另一组答案 \texttt{5 206}
\sout{所以这题有两组解:} \texttt{0 207} 和 \texttt{5 206} 
发现不知为何，前几次好像读入 \texttt{6 682} 后没过（是我的错觉？），后来再试了下，发现是可以过的。
而且前几次 debug 的时候一直用 \texttt{x/x \$rsp+0xc} ，打印结果也一直是一个字节，后来发现应该用 \texttt{x/xw \$rsp+0xc} ，读入值的结果就显示正确了。默认输出似乎是一个字节地输出。
所以这题答案应该有 8 组：
\begin{center}
\begin{tabular}{l}
0 207\\
1 311\\
2 707\\
3 256\\
4 389\\
5 206\\
6 682\\
7 327\\
\end{tabular}
\end{center}

\section{phase\(_{\text{4}}\)}
\label{sec:orgc6692ea}

这道题同样输入两个整数，要求第一个数小于等于 14。其中调用了一个 \texttt{fun4} 的函数。
我将这个函数写成 C 的代码，根据代码知道 \texttt{phase\_4} 在调用这个函数时，第二、三个参数分别为 0，14，而第一个参数就是输入的第一个数。

\begin{verbatim}
#include <stdio.h>

int fun4(int x, int y, int z)
{
  int i = z - y, j = i >> 31;
  i = (i + j) / 2;
  j = i + y;
  if (j > x)
  {
    z = j - 1;
    fun4(x, y, z);
    i = i + i;
  }
  else
  {
    i = 0;
    if (j < x)
    {
      y = j + 1;
      fun4(x, y, z);
      i = 2 * i + 1;
    }
  }

}

int main(void)
{
  for (int i = 0; i < 15; i++)
    printf("%d : %d\n", i, fun4(i, 0, 14));

  return 0;
}
\end{verbatim}

我把第一个数所有情况的返回值都打印了一遍。

Output:

\begin{verbatim}
0 : 0
1 : 1
2 : 1
3 : 3
4 : 1
5 : 1
6 : 1
7 : 7
8 : 1
9 : 1
10 : 1
11 : 1
12 : 1
13 : 1
14 : 1
\end{verbatim}

后面的代码中要求返回值为 0，而且第二个数也为 0，所以显然输入的答案是 \texttt{0 0}

\section{phase\(_{\text{5}}\)}
\label{sec:orgc450bd8}

容易看出 \texttt{phase\_5} 读入一个长度为 6 的字符串，中间有一个进行 6 次的循环，依次对每一个读入的字符进行一种映射，生成一个新的字符串。我们需要使新字符串与目标字符串 \texttt{"flyers"} 完全匹配。
而其中关键在于一句话： \texttt{movzbl 0x4024b0(\%rdx),\%edx} 内存中储存了一个字符到字符的映射，也就是数组。将其打印出来：

\begin{verbatim}
(gdb) x/255cb 0x402460
0x402460:	121 'y'	101 'e'	114 'r'	115 's'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402468:	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402470:	124 '|'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402478:	-71 '\271'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402480:	-125 '\203'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402488:	-118 '\212'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402490:	-111 '\221'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402498:	-104 '\230'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x4024a0:	-97 '\237'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x4024a8:	-90 '\246'	15 '\017'	64 '@'	0 '\000'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x4024b0 <array.3449>:	109 'm'	97 'a'	100 'd'	117 'u'	105 'i'	101 'e'	114 'r'	115 's'
0x4024b8 <array.3449+8>:	110 'n'	102 'f'	111 'o'	116 't'	118 'v'	98 'b'	121 'y'	108 'l'
0x4024c0:	83 'S'	111 'o'	32 ' '	121 'y'	111 'o'	117 'u'	32 ' '	116 't'
0x4024c8:	104 'h'	105 'i'	110 'n'	107 'k'	32 ' '	121 'y'	111 'o'	117 'u'
0x4024d0:	32 ' '	99 'c'	97 'a'	110 'n'	32 ' '	115 's'	116 't'	111 'o'
0x4024d8:	112 'p'	32 ' '	116 't'	104 'h'	101 'e'	32 ' '	98 'b'	111 'o'
0x4024e0:	109 'm'	98 'b'	32 ' '	119 'w'	105 'i'	116 't'	104 'h'	32 ' '
0x4024e8:	99 'c'	116 't'	114 'r'	108 'l'	45 '-'	99 'c'	44 ','	32 ' '
0x4024f0:	100 'd'	111 'o'	32 ' '	121 'y'	111 'o'	117 'u'	63 '?'	0 '\000'
0x4024f8:	67 'C'	117 'u'	114 'r'	115 's'	101 'e'	115 's'	44 ','	32 ' '
0x402500:	121 'y'	111 'o'	117 'u'	39 '\''	118 'v'	101 'e'	32 ' '	102 'f'
0x402508:	111 'o'	117 'u'	110 'n'	100 'd'	32 ' '	116 't'	104 'h'	101 'e'
0x402510:	32 ' '	115 's'	101 'e'	99 'c'	114 'r'	101 'e'	116 't'	32 ' '
0x402518:	112 'p'	104 'h'	97 'a'	115 's'	101 'e'	33 '!'	0 '\000'	0 '\000'
0x402520:	66 'B'	117 'u'	116 't'	32 ' '	102 'f'	105 'i'	110 'n'	100 'd'
0x402528:	105 'i'	110 'n'	103 'g'	32 ' '	105 'i'	116 't'	32 ' '	97 'a'
0x402530:	110 'n'	100 'd'	32 ' '	115 's'	111 'o'	108 'l'	118 'v'	105 'i'
0x402538:	110 'n'	103 'g'	32 ' '	105 'i'	116 't'	32 ' '	97 'a'	114 'r'
0x402540:	101 'e'	32 ' '	113 'q'	117 'u'	105 'i'	116 't'	101 'e'	32 ' '
0x402548:	100 'd'	105 'i'	102 'f'	102 'f'	101 'e'	114 'r'	101 'e'	110 'n'
0x402550:	116 't'	46 '.'	46 '.'	46 '.'	0 '\000'	0 '\000'	0 '\000'	0 '\000'
0x402558:	67 'C'	111 'o'	110 'n'	103 'g'	114 'r'	97 'a'	116 't'
\end{verbatim}

其中很多我们不能输入的字符，所以要尽量在二十六个字母的大小写及其附近寻找我们需要的字符，也就是最好在 0x4024a0 和 0x4024c0 之后查找（貌似在 <array.3449> 中查找就够了），算出对应 ascii 码的值找到相应原字符。
我得出的一个结果是 \texttt{"Y\_\textasciicircum{}UVW"}

\section{phase\(_{\text{6}}\)}
\label{sec:org5e9980f}

\texttt{phase\_6} 很长（对于比较复杂的部分我将汇编代码先简化地表达出来，然后再对着这个笔记重新写成 C 的代码的格式，方便理解），首先调用相同的函数 \texttt{read\_six\_numbers} 读入六个数，之后从 \texttt{0x401114 <phase\_6+32>} 到 \texttt{0x401151 <phase\_6+93>} 都在做同一件事：判断存入数组中的 6 个数是否都小于 6，而且是否都不重复。若不满足条件，炸弹就会爆炸。
在这后面直到 \texttt{0x40116d <phase\_6+121>} 这段程序在将所得六个数逐个用 7 减去并放回原来的位置。
再后面直到 \texttt{0x4011ab <phase\_6+183>} 这段程序将处理后的六个数中第 i 个数 x 逐个映射到一个含有六个节点的链表的第 x 个节点的地址，从而产生一个新的数组，数组元素是指向链表节点的指针。
后面直到 \texttt{0x4011d0 <phase\_6+220>} 这段程序将新数组中的链表节点依照数组的前后顺序连接起来。
最后到结束这一部分判断生成的新链表节点的数值是否是依次递减的。如果不是则会爆炸。

对应原链表节点中的数据如下：
\begin{center}
\begin{tabular}{lr}
Node1 & 0x14c\\
Node2 & 0xa8\\
Node3 & 0x39c\\
Node4 & 0x2b3\\
Node5 & 0x1dd\\
Node6 & 0x1bb\\
\end{tabular}
\end{center}

根据程序功能逆向推导就可以得出原输入的 1-6 六个数的序列为： \texttt{4 3 2 1 6 5}

\section{secret\(_{\text{phase}}\)}
\label{sec:orgd82bd60}

首先要找到 \texttt{secret\_phase} 的调用，发现只在 \texttt{phase\_defused} 中出现了调用。而且考虑到是在六个 \texttt{phase} 都通过的情况下才可能出现 \texttt{secret\_phase} ，所以考虑在 \texttt{main} 函数调用 \texttt{phase\_6} 函数之后的那个 \texttt{phase\_defused} 设置一个断点。
运行进入 \texttt{phase\_defused} 后，发现调用了一次 \texttt{sscanf} 函数，在即将调用前查看寄存器 \$rdi \$rsi 中存储的字符串发现，参数中第一个字符串是我们输入的 \texttt{"0 0"} 那一行，第二个字符串参数是 \texttt{"\%d \%d \%s"} 说明还需要我们输入一个字符串，之后调用了字符串比较函数，查看其中一个参数的内存 0x402622 中存放的字符串为 \texttt{"DrEvil"} 所以在那一行加上这个字符串。
接着就进入了 \texttt{secret\_phase} 函数。函数里先读入一行字符串，然后调用了 \texttt{strtol} 函数，将字符串中的长整数转化为长整型，之后便调用 \texttt{fun7} 函数，参数传递了一个地址和这个输入的数。而且要求函数返回值为 2 的时候才能拆除炸弹。
在 \texttt{fun7} 中使用了一种递归的形式。大体逻辑是：判断第一个地址 a 是否为空，是则返回 0xffffffff，否则根据地址中存储的数 x 与第二个参数 b 的大小关系返回值。假设返回值为 ans
当 x > b 时， \texttt{ans = 2 * fun7(*(a + 8), b)}
当 x = b 时， \texttt{ans = 0}
当 x < b 时， \texttt{ans = 1 + 2 * fun7(*(a + 16), b)}
可以看出 a 应该是一个链表结构。
我手动逐个查看了几个链表节点的数据，但是数据似乎太多了，于是将表头的内存地址开始的许多地址信息全都打印出来，删除多余信息后得到下面数据：

\begin{verbatim}
0x6030f0 <n1>:	0x0000000000000024	0x0000000000603110
0x603100 <n1+16>:	0x0000000000603130	0x0000000000000000
0x603110 <n21>:	0x0000000000000008	0x0000000000603190
0x603120 <n21+16>:	0x0000000000603150	0x0000000000000000
0x603130 <n22>:	0x0000000000000032	0x0000000000603170
0x603140 <n22+16>:	0x00000000006031b0	0x0000000000000000
0x603150 <n32>:	0x0000000000000016	0x0000000000603270
0x603160 <n32+16>:	0x0000000000603230	0x0000000000000000
0x603170 <n33>:	0x000000000000002d	0x00000000006031d0
0x603180 <n33+16>:	0x0000000000603290	0x0000000000000000
0x603190 <n31>:	0x0000000000000006	0x00000000006031f0
0x6031a0 <n31+16>:	0x0000000000603250	0x0000000000000000
0x6031b0 <n34>:	0x000000000000006b	0x0000000000603210
0x6031c0 <n34+16>:	0x00000000006032b0	0x0000000000000000
0x6031d0 <n45>:	0x0000000000000028	0x0000000000000000
0x6031e0 <n45+16>:	0x0000000000000000	0x0000000000000000
0x6031f0 <n41>:	0x0000000000000001	0x0000000000000000
0x603200 <n41+16>:	0x0000000000000000	0x0000000000000000
0x603210 <n47>:	0x0000000000000063	0x0000000000000000
0x603220 <n47+16>:	0x0000000000000000	0x0000000000000000
0x603230 <n44>:	0x0000000000000023	0x0000000000000000
0x603240 <n44+16>:	0x0000000000000000	0x0000000000000000
0x603250 <n42>:	0x0000000000000007	0x0000000000000000
0x603260 <n42+16>:	0x0000000000000000	0x0000000000000000
0x603270 <n43>:	0x0000000000000014	0x0000000000000000
0x603280 <n43+16>:	0x0000000000000000	0x0000000000000000
0x603290 <n46>:	0x000000000000002f	0x0000000000000000
0x6032a0 <n46+16>:	0x0000000000000000	0x0000000000000000
0x6032b0 <n48>:	0x00000000000003e9	0x0000000000000000
0x6032c0 <n48+16>:	0x0000000000000000	0x0000000000000000
\end{verbatim}

因为最终结果需要的返回值是 2，所以逆推过来肯定是 \texttt{2 = 2 * 1} <= \texttt{1 = 1 + 2 * 0} <= \texttt{0}
按照思路就应该是 <n1> -> <n21> -> <n32> ，恰好当 b = 0x16 时满足所有条件，所以输入的值为 \texttt{22} 

\section{总结}
\label{sec:org9ce63dd}

所有输入数据：

\begin{verbatim}
Border relations with Canada have never been better.
1 2 4 8 16 32
5 206
0 0 DrEvil
Y_^UVW
4 3 2 1 6 5
22
\end{verbatim}
\end{document}
